#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include "MQTTClient.h"
#include "cJSON.h"
#include "shmem.h"
#include "datareportfun.h"
#include "msgqueue.h"
#include "historyreport.h"
#define TEMPERATURE 301
#define HUMIDITY 302
struct treadx
{
    int nodenumber;
    int time;
    sqlite3 *datebase;
    struct std_node *stmmod;
};
int nodenum;
int msgid;
struct std_node *stm_mod;
sqlite3 *db;
void *handler_thread(void *arg);
void clicked_report(void *arg);
void *change_report(void *arg);
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    char *payloadptr;
    payloadptr = message->payload;
    cJSON *root = cJSON_Parse(payloadptr);
    cJSON *type = cJSON_GetObjectItem(root, "type");
    if (type->valueint == 1)
    {
        int fd = open("/home/hq/24011/project/datapot.json", O_RDWR | O_CREAT | O_APPEND, 0666);
        if (fd < 0)
        {
            perror("file open err!");
        }
        char buff[2048];
        char buff1[2048];
        int n = read(fd, buff1, 2048);
        memcpy(buff, buff1, n);

        static struct treadx ptreadxy;
        cJSON *datapot = cJSON_Parse(buff);
        cJSON *report = cJSON_GetObjectItem(datapot, "report");
        cJSON *tim = cJSON_GetObjectItem(report, "period");
        ptreadxy.time = (int)(tim->valueint);
        ptreadxy.nodenumber = nodenum;
        cJSON *reportmode = cJSON_GetObjectItem(report, "type");
        if (reportmode->valueint == 0)
        {
            clicked_report(&ptreadxy);
        }
        else if (reportmode->valueint == 1)
        {
            pthread_t tid;
            if (pthread_create(&tid, NULL, change_report, &ptreadxy) != 0)
            {
                perror("thread err");
                return -1;
            }
        }
        else if (reportmode->valueint == 2)
        {
            pthread_t tid;
            if (pthread_create(&tid, NULL, handler_thread, &ptreadxy) != 0)
            {
                perror("thread err");
                return -1;
            }
        }
    }
    else if (type->valueint == 2)
    {
        cJSON *data = cJSON_GetObjectItem(root, "data");
        cJSON *key = cJSON_GetObjectItem(data, "key");
        cJSON *val = cJSON_GetObjectItem(data, "val");
        struct msgbuf msg;
        if (key->valueint > 300)
        {
            msg.type = 1;
        }
        else
        {
            msg.type = 2;
        }
        msg.key = key->valueint;
        strcpy(msg.val, val->valuestring);
        msgsnd(msgid, &msg, sizeof(msg) - sizeof(long), 0); // 0：代表发完返回否则阻塞
    }
    else if (type->valueint == 3)
    {
        cJSON *data = cJSON_GetObjectItem(root, "data");
        FILE *file = fopen("/home/hq/24011/project/datapot.json", "r");
        if (!file)
        {
            printf("无法打开datapotlist\n");
            return 1;
        }
        // 读取文件内容
        fseek(file, 0, SEEK_END);
        long file_size = ftell(file);
        fseek(file, 0, SEEK_SET);
        char *buffer = (char *)malloc(file_size + 1);
        fread(buffer, 1, file_size, file);
        fclose(file);
        buffer[file_size] = '\0'; // 确保字符串以null结尾
        // 解析JSON
        cJSON *roothead = cJSON_Parse(buffer);
        if (!roothead)
        {
            printf("解析JSON失败\n");
            return 1;
        }
        // 修改"report"的属性
        cJSON_ReplaceItemInObject(roothead, "report", data);
        // 将修改后的JSON重新序列化
        char *json_string = cJSON_Print(roothead);
        if (!json_string)
        {
            printf("转换为字符串失败\n");
            return 1;
        }
        // 保存修改后的JSON到文件
        FILE *output_file = fopen("/home/hq/24011/project/datapot.json", "w");
        if (!output_file)
        {
            printf("无法打开输出文件\n");
            return 1;
        }
        fwrite(json_string, 1, strlen(json_string), output_file);
        fclose(output_file);
        // 清理
        free(buffer);
        cJSON_Delete(root);
        free(json_string);
        printf("JSON文件已成功修改并保存\n");
    }
    else if (type->valueint == 4)
    {
        char sql[32];
        char *errmsg;
        char **result = NULL;
        int nrow;
        cJSON *data = cJSON_GetObjectItem(root, "data");
        cJSON *key = cJSON_GetObjectItem(data, "key");
        cJSON *limit = cJSON_GetObjectItem(data, "limit");
        cJSON *down1 = cJSON_GetArrayItem(limit, 0);
        cJSON *up1 = cJSON_GetArrayItem(limit, 1);
        long down = (long)down1->valueint;
        long up = (long)up1->valueint;
        if (key->valueint == TEMPERATURE)
        {
            sprintf(sql, "select * from temperature where time>%ld and time<%ld;", down, up);
            sqlite3_get_table(db, sql, &result, &nrow, NULL, &errmsg);
            printf("%d\n",nrow);
        }

        if (key->valueint == HUMIDITY)
        {
            sprintf(sql, "select * from humidity where time>%ld and time<%ld;", down, up);
            sqlite3_get_table(db, sql, &result, &nrow, NULL, &errmsg);
        }
        if (nrow > 1)
            {
                cJSON *sendroot = cJSON_CreateObject();
                cJSON_AddItemToObject(sendroot, "type", cJSON_CreateNumber(4));
                cJSON_AddItemToObject(sendroot, "result", cJSON_CreateNumber(0));
                cJSON_AddItemToObject(sendroot, "key", cJSON_CreateNumber(TEMPERATURE));
                cJSON *data = cJSON_CreateArray();
                for (int i = 1; i <= nrow; i++)
                {
                    cJSON *datanode = cJSON_CreateObject();
                    cJSON_AddItemToObject(datanode, "time", cJSON_CreateString(result[2*i]));
                    cJSON_AddItemToObject(datanode, "val", cJSON_CreateString(result[2*i+1]));
                    cJSON_AddItemToArray(data,datanode);
                }
                cJSON_AddItemToObject(sendroot,"data",data);
                char *p = cJSON_Print(sendroot);
                printf("%s\n", p);
                mqttpublish(p);  
            }
    }
    putchar('\n');
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}
void clicked_report(void *arg)
{
    cJSON *root = cJSON_CreateObject();
    //创建name节点并添加到根节点中
    cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(1));
    cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));

    //创建data节点
    cJSON *data = cJSON_CreateArray();
    for (int i = 0; i < (*(struct treadx *)arg).nodenumber; i++) //-----------------------------------------------question---------
    {
        cJSON *dev = cJSON_CreateObject();
        cJSON_AddItemToObject(dev, "key", cJSON_CreateNumber((stm_mod + i)->key));
        char value[24];
        if ((stm_mod + i)->type == 1)
        {

            sprintf(value, "%d", (stm_mod + i)->new_val.b_val);
        }
        else if ((stm_mod + i)->type == 2)
        {

            sprintf(value, "%d", (stm_mod + i)->new_val.i_val);
        }
        else if ((stm_mod + i)->type == 3)
        {

            sprintf(value, "%f", (stm_mod + i)->new_val.f_val);
        }  
        cJSON_AddItemToObject(dev, "val", cJSON_CreateString(value));
        cJSON_AddItemToArray(data, dev);
    }
    //将array节点添加到根节点上
    cJSON_AddItemToObject(root, "data", data);
    //序列化成json字符串
    char *p = cJSON_Print(root);
    printf("%s\n", p);
    mqttpublish(p);
}
void *handler_thread(void *arg)
{
    while (1)
    {
        cJSON *root = cJSON_CreateObject();
        //创建name节点并添加到根节点中
        cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(1));
        cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));

        //创建data节点
        cJSON *data = cJSON_CreateArray();
        for (int i = 0; i < (*(struct treadx *)arg).nodenumber; i++) //-----------------------------------------------question---------
        {
            cJSON *dev = cJSON_CreateObject();
            cJSON_AddItemToObject(dev, "key", cJSON_CreateNumber((stm_mod + i)->key));
            char value[24];
            if ((stm_mod + i)->type == 1)
            {

                sprintf(value, "%d", (stm_mod + i)->new_val.b_val);
            }
            else if ((stm_mod + i)->type == 2)
            {

                sprintf(value, "%d", (stm_mod + i)->new_val.i_val);
            }
            else if ((stm_mod + i)->type == 3)
            {

                sprintf(value, "%f", (stm_mod + i)->new_val.f_val);
            }
            cJSON_AddItemToObject(dev, "val", cJSON_CreateString(value));
            cJSON_AddItemToArray(data, dev);
        }
        //将array节点添加到根节点上
        cJSON_AddItemToObject(root, "data", data);
        //序列化成json字符串
        char *p = cJSON_Print(root);
        printf("%s\n", p);
        mqttpublish(p);
        sleep((*(struct treadx *)arg).time);
    }
}
void *change_report(void *arg)
{
    while (1)
    {
        int change_node_num = 0;
        char *p;
        cJSON *root = cJSON_CreateObject();
        //创建name节点并添加到根节点中
        cJSON_AddItemToObject(root, "type", cJSON_CreateNumber(1));
        cJSON_AddItemToObject(root, "result", cJSON_CreateNumber(0));

        //创建data节点
        cJSON *data = cJSON_CreateArray();
        for (int i = 0; i < (*(struct treadx *)arg).nodenumber; i++) //-----------------------------------------------question---------
        {
            if (((stm_mod + i)->new_val.i_val) != ((stm_mod + i)->old_val.i_val) || ((stm_mod + i)->new_val.b_val) != ((stm_mod + i)->old_val.b_val) || ((stm_mod + i)->new_val.f_val) != ((stm_mod + i)->old_val.f_val))
            {
                change_node_num++;
                cJSON *dev = cJSON_CreateObject();
                cJSON_AddItemToObject(dev, "key", cJSON_CreateNumber((stm_mod + i)->key));
                char value[24];
                if ((stm_mod + i)->type == 1)
                {

                    sprintf(value, "%d", (stm_mod + i)->new_val.b_val);
                }
                else if ((stm_mod + i)->type == 2)
                {
                    sprintf(value, "%d", (stm_mod + i)->new_val.i_val);
                }
                else if ((stm_mod + i)->type == 3)
                {
                    sprintf(value, "%f", (stm_mod + i)->new_val.f_val);
                }
                cJSON_AddItemToObject(dev, "val", cJSON_CreateString(value));
                cJSON_AddItemToArray(data, dev);
            }
            
        }
        cJSON_AddItemToObject(root, "data", data);
        
        
        if (change_node_num > 0)
        {
            //将array节点添加到根节点上
        
            //序列化成json字符串
            p = cJSON_Print(root);
            printf("%s\n", p);
            // printf("%d\n",change_node_num );
            mqttpublish(p);
        }
    }
}
void *data_insert_database(void *arg)
{
    struct treadx *ptdxy = (struct treadx *)arg;
    char sql[32];
    char *errmsg;
    char **result = NULL;
    int nrow;
    float temperature;
    float humidity;

    time_t tm;
    while (1)
    {
        for (int i = 0; i < ptdxy->nodenumber; i++)
        {
            if ((stm_mod + i)->key == TEMPERATURE)
            {
                temperature = (stm_mod + i)->new_val.f_val;
            }
            if ((stm_mod + i)->key == HUMIDITY)
            {
                humidity = (stm_mod + i)->new_val.f_val;
            }
        }
        tm = time(NULL);
        
        sprintf(sql, "insert into temperature values(%ld,%f);", (long)tm, temperature);
        if (sqlite3_exec(ptdxy->datebase, sql, NULL, NULL, &errmsg) != SQLITE_OK)
        {
            printf("insert temperature err!  %s\n",errmsg);
        }
        sprintf(sql, "insert into humidity values(%ld,%f);", (long)tm, humidity);
        if (sqlite3_exec(ptdxy->datebase, sql, NULL, NULL, &errmsg) != SQLITE_OK)
        {
            printf("insert humidity err!\n");
        }
        sleep(5);
    }
}
void insert_database(void)
{
    static struct treadx ptdxy;
    ptdxy.nodenumber = nodenum;
    ptdxy.datebase = db;
    ptdxy.stmmod = stm_mod;
    pthread_t tidd;
    if (pthread_create(&tidd, NULL, data_insert_database, &ptdxy) != 0)
    {
        perror("thread err");
        return;
    }
}
int main(int argc, char *argv[])
{
    db = database_init();
    struct shm_param head = shm_creat(&nodenum);
    
    int *nodenum = (int *)shm_getaddr(&head);
    stm_mod = (struct std_node *)(nodenum + 1);
    msgid = msgqueue_create();
    mqttsubscrib();
    insert_database();
    // stm_mod->old_val.f_val=100;
    // (stm_mod+1)->old_val.f_val=100;
    // (stm_mod+1)->new_val.f_val=100;
    // while(1)
    // {
    //     stm_mod->new_val.f_val=100;
    //     stm_mod->old_val.f_val=100;
    //     sleep(1);
    //     stm_mod->new_val.f_val=200;
    //     stm_mod->old_val.f_val=100;
    //     sleep(1);
    // }
    while (1)
    {
    //     struct msgbuf m;
    // msgrcv(msgid, &m, sizeof(m) - sizeof(long), 2, 0);
    // printf("%ld %d %s\n",m.type,m.key,m.val);
        

    }
}
